package org.example.seata.bs.account.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import lombok.AllArgsConstructor;
import org.example.seata.bs.account.service.AccountEnhanceService;
import org.example.seata.bs.api.dto.account.AccountBalanceLogDto;
import org.example.seata.bs.api.entity.account.Account;
import org.example.seata.bs.api.entity.account.AccountBalanceLog;
import org.example.seata.bs.api.service.account.AccountBalanceLogService;
import org.example.seata.bs.api.service.account.impl.AccountServiceImpl;
import org.example.seata.bs.api.vo.account.AccountBalanceLogVo;
import org.example.seata.common.core.constant.LKC;
import org.example.seata.common.core.util.ApiResp;
import org.example.seata.common.core.util.BusOp;
import org.example.seata.common.security.util.SecurityUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;

/**
 * @author hzq
 * @date 2021/11/30 14:41
 */
@Service
@Primary
@DS("account")
@AllArgsConstructor
public class AccountEnhanceServiceImpl extends AccountServiceImpl implements AccountEnhanceService {

    private final LockTemplate lockTemplate;
    private final AccountBalanceLogService accountBalanceLogService;

    @Override
    public ApiResp<AccountBalanceLogVo> minusAccountBalance(AccountBalanceLogDto dto) {
        Integer accountId = SecurityUtil.getAuth().getAccountId();
        LockInfo lock = lockTemplate.lock(LKC.Account.ACCOUNT_BALANCE.getLockKey(accountId));
        try {
            AccountBalanceLogVo logVo = new AccountBalanceLogVo();
            Account account = getById(accountId);
            BusOp.mustNotNull(account, "用户不存在");
            // 为空的话默认余额为零
            BigDecimal accountBalance = BusOp.defaultValue(account.getAccountBalance(), BigDecimal.ZERO);
            // 当前余额
            BigDecimal currentBalance = accountBalance.add(dto.getLogBalance());
            if (currentBalance.compareTo(BigDecimal.ZERO) < 0) {
                logVo.setCurrentBalance(account.getAccountBalance()).setDescription("操作失败")
                        .setLogBalance(dto.getLogBalance()).setOperateResult(Boolean.FALSE);
                return ApiResp.ofError("用户余额不足", logVo);
            }
            account.setAccountBalance(currentBalance);
            // 插入余额操作日志
            BusOp.mustSucceed(accountBalanceLogService.save(createAccountBalanceLog(dto).setAccountId(accountId)), "插入余额操作日志失败");
            // 修改账户余额
            BusOp.mustSucceed(updateById(account), "修改账户余额失败");

            logVo.setCurrentBalance(currentBalance).setDescription("操作成功")
                    .setLogBalance(dto.getLogBalance()).setOperateResult(Boolean.TRUE);
            return ApiResp.ofSuccess(logVo);
        } finally {
            lockTemplate.releaseLock(lock);
        }
    }

    /**
     * 封装金额日志
     */
    AccountBalanceLog createAccountBalanceLog(AccountBalanceLogDto dto) {
        AccountBalanceLog log = new AccountBalanceLog();
        BeanUtils.copyProperties(dto, log);
        return log;
    }
}
